package com.net.xpay.core.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AccDetailModel;
import com.alipay.api.response.AlipayFundBatchCloseResponse;
import com.alipay.api.response.AlipayFundBatchCreateResponse;
import com.alipay.api.response.AlipayFundBatchDetailQueryResponse;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserProfile;
import com.net.xpay.common.domain.notify.ChargeNotifyRecord;
import com.net.xpay.common.enums.config.CommonSysConfigKey;
import com.net.xpay.common.enums.notify.NotifyStatus;
import com.net.xpay.common.enums.user.CommissionMode;
import com.net.xpay.common.enums.user.ServicePayMode;
import com.net.xpay.common.helper.CommonSysConfigHelper;
import com.net.xpay.common.helper.NoticeHelper;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.UserProfileManager;
import com.net.xpay.core.constant.CoreConstant;
import com.net.xpay.core.constant.PayMethod;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.xpay.core.constant.TransBizTypeConstant;
import com.net.xpay.core.domain.*;
import com.net.xpay.core.enums.*;
import com.net.xpay.core.manager.*;
import com.net.common.annotation.WriteTransactional;
import com.net.common.exception.BusinessException;
import com.net.common.util.LocalDateUtil;
import com.net.common.util.SerializationUtil;
import com.net.common.util.StreamUtil;
import com.net.xpay.alipay.AlipayProperties;
import com.net.xpay.alipay.PoseidonAlipayClient;
import com.net.xpay.alipay.model.TransOrderModel;
import com.net.xpay.common.manager.notify.ChargeNotifyRecordManager;
import com.net.xpay.common.manager.partner.PartnerCodeManager;
import com.net.xpay.core.CoreProperties;
import com.net.xpay.core.domain.*;
import com.net.xpay.core.dto.PayTransBatchDto;
import com.net.xpay.core.dto.PayTransBatchV2Dto;
import com.net.xpay.core.dto.PayTransDto;
import com.net.xpay.core.enums.*;
import com.net.xpay.core.helper.AccountDetailHelper;
import com.net.xpay.core.helper.PayTransErrorMsgHelper;
import com.net.xpay.core.helper.QrCodeHelper;
import com.net.xpay.core.manager.*;
import com.net.xpay.core.service.AccountService;
import com.net.xpay.core.service.AlipayFundBatchService;
import com.net.xpay.core.service.CollectionOrderService;
import com.net.xpay.core.service.PayTransBatchService;
import com.net.xpay.core.service.auto.AutoPayService;
import com.net.xpay.core.utils.BeanCopierUtil;
import com.net.xpay.core.utils.GsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * 2020/5/8 15:25

 *
 * @author anno
 */
@Slf4j
@Service
@WriteTransactional
public class PayTransBatchServiceImpl implements PayTransBatchService {

    @Autowired
    private PayTransBatchManager payTransBatchManager;

    @Autowired
    private PoseidonAlipayClient xpayAlipayClient;

    @Autowired
    private AlipayUserManager alipayUserManager;

    @Autowired
    private PayTransSummaryManager payTransSummaryManager;

    @Autowired
    private PayTransRecordManager payTransRecordManager;

    @Autowired
    private PayTransManager payTransManager;

    @Autowired
    private AlipayProperties alipayProperties;

    @Autowired
    private AlipayFundBatchService alipayFundBatchService;

    @Autowired
    private UserManager userManager;

    @Autowired
    private UserAccountManager userAccountManager;

    @Autowired
    private AccountService accountService;

    @Autowired
    private AccountDetailHelper accountDetailHelper;

    @Autowired
    private AccountDetailManager accountDetailManager;

    @Autowired
    private NoticeHelper noticeHelper;

    @Autowired
    private PayTransErrorMsgHelper payTransErrorMsgHelper;

    @Autowired
    private ChargeNotifyRecordManager chargeNotifyRecordManager;

    @Autowired
    private UserProfileManager userProfileManager;

    @Autowired
    private CoreProperties coreProperties;

    @Autowired
    private ChargeRecordManager chargeRecordManager;

    @Autowired
    private CommonSysConfigHelper commonSysConfigHelper;

    @Autowired
    private QrCodeHelper qrCodeHelper;

    @Autowired
    private CollectionOrderService collectionOrderService;

    @Autowired
    private PartnerCodeManager partnerCodeManager;

    @Autowired
    private AutoPayService autoPayService;


    @Override
    public PayTransBatch batchPayTrans(User user, Long id, String alipayNickName, String signBizNo, String returnUrl, Integer payMethod) {
        Preconditions.checkArgument(id != null);
        UserAccount userAccount = userAccountManager.getByIdWithLock(user.getId());

        PayTransBatch payTransBatch = payTransBatchManager.findById(user.getId(), id);
        if (payTransBatch == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "打款批次不存在");
        }
        if (payTransBatch.getStatus() != PayTransBatchStatus.IMPORTED && payTransBatch.getStatus() != PayTransBatchStatus.DISUSE) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "当前打款批次已处理，请勿重复操作");
        }

        if (Boolean.TRUE.equals(payTransBatch.getOtherTrans())) {
            log.error("batchPayTrans error|not support method pay|id={}", id);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "此批次不支持用该方式支付");
        }
        //移动端支付不能超过200笔
        if (payMethod != null && !payMethod.equals(PayMethod.PC)) {
            if (payTransBatch.getTotalCount() > 200L) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "移动端支付单批次不能超过200笔");
            }
        }

        AlipayUser alipayUser;
        if (!Strings.isNullOrEmpty(alipayNickName)) {
            alipayUser = alipayUserManager.findByAlipayNickName(user.getId(), alipayNickName);
            if (alipayUser == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "付款方支付宝账号不存在");
            }
        } else if(!Strings.isNullOrEmpty(signBizNo)) {
            alipayUser = alipayUserManager.findBySignBizNo(user.getId(), signBizNo);
            if (alipayUser == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "付款方支付宝账号不存在");
            }
        } else {
            if (user.getAlipayUserId() == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请先绑定支付宝账号");
            }
            alipayUser = alipayUserManager.getById(user.getAlipayUserId());
        }

        if (alipayUser == null || alipayUser.getStatus() != AlipayUserStatus.YES) {
            throw new BusinessException(PoseidonErrorCode.INVALID_APP_AUTH_TOKEN, "你的支付宝账号尚未签约，请先签约后再打款");
        }

        if (userAccount.getMoneyLeft() < payTransBatch.getServicePrice() && !(userAccount.getTransBatchLeft() > 0L && new BigDecimal(payTransBatch.getTotalTransAmount()).compareTo(CoreConstant.MAX_TRANS_FREE_AMOUNT) <= 0) ) {
            throw new BusinessException(PoseidonErrorCode.MONEY_NOT_ENOUGH, "服务费账户余额不足，请充值");
        }
        //有剩余的批次次数
        checkHasLeftTransBatch(userAccount, payTransBatch, alipayUser);

        //记录此次发起的批次交易记录
        PayTransSummary payTransSummary = createPayTransSummary(user, alipayUser, payTransBatch);
        List<PayTransRecord> payTransRecords = createPayTransRecords(payTransSummary);

        //创建支付宝批量打款订单
        alipayFundBatchCreate(payTransSummary, payTransRecords, alipayUser);

        //发起支付链接
        if (Strings.isNullOrEmpty(returnUrl)) {
            returnUrl = alipayProperties.getTransReturnUrl() + "?payTransBatchId=" + payTransBatch.getId();
        }

        try {
            //生成PC端支付链接
            String payUrl = xpayAlipayClient.alipayFundTransPagePay(alipayUser.getAuthToken(), payTransSummary.getBatchTransId(), returnUrl);
            payTransBatch.setLastPayUrl(payUrl);
            //生成移动端支付链接和二维码链接
            if (payMethod != null && !payMethod.equals(PayMethod.PC)) {
                createMobilePayUrl(payTransBatch, payTransSummary, alipayUser, returnUrl);
            }

            payTransBatch.setStatus(PayTransBatchStatus.WAIT_PAY);
            payTransBatch.setBatchTransId(payTransSummary.getBatchTransId());
            payTransBatchManager.updateByPrimaryKeyWithVersion(payTransBatch);
            payTransManager.updateStatusByPayTransBatchId(user.getId(), payTransBatch.getId(), PayTransStatus.WAIT_PAY, payTransBatch.getFree(), null);
            payTransSummary.setStatus(PayTransBatchStatus.WAIT_PAY);
            payTransSummaryManager.updateByPrimaryKeyWithVersion(payTransSummary);

            //预扣服务费
            payServiceMoney(user, userAccount, payTransBatch);

            return payTransBatch;
        } catch (Exception e) {
            log.warn("batchPayTrans error|userId={}|id={}", id, e);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "系统繁忙");
        }
    }

    private void createMobilePayUrl(PayTransBatch payTransBatch, PayTransSummary payTransSummary, AlipayUser alipayUser, String returnUrl) throws IOException {
        String mobilePayUrl = xpayAlipayClient.alipayFundBatchAppPay(alipayUser.getAuthToken(), payTransSummary.getBatchTransId(), returnUrl);

        // 初始支付参数
        String param = mobilePayUrl.substring(mobilePayUrl.indexOf("?") + 1);
        // 将支付参数整体 encode 一次
        String encodeParam = URLEncoder.encode(param, "utf-8");
        // 拼接带参页面路径并再次整体encode
        String pageEncode = URLEncoder.encode("pages/confirm/index/index?signParams=" + encodeParam, "utf-8");
        // 拼接跳转支付宝内支付地址
        mobilePayUrl = "alipays://platformapi/startapp?appId=2021002133661287&appClearTop=false&startMultApp=YES"
                + "&page=" + pageEncode;

        // 拼接完整跳转链接
        mobilePayUrl = "https://render.alipay.com/p/s/ulink/?scheme=" + URLEncoder.encode(mobilePayUrl, "utf-8");
        payTransBatch.setLastMobilePayUrl(mobilePayUrl);

        //二维码链接地址
        String qrCode = qrCodeHelper.genThenUpload(alipayProperties.getMobilePayBaseUrl() + payTransSummary.getOutBatchNo());
        payTransBatch.setMobilePayQrCode(qrCode);
    }

    private void checkHasLeftTransBatch(UserAccount userAccount, PayTransBatch payTransBatch, AlipayUser alipayUser) {
        if (userAccount.getTransBatchLeft() > 0L && new BigDecimal(payTransBatch.getTotalTransAmount()).compareTo(CoreConstant.MAX_TRANS_FREE_AMOUNT) <= 0) {
            payTransBatch.setFree(true);
            payTransBatch.setServiceRealPrice(0L);
            payTransBatch.setServicePrice(0L);
            payTransBatch.setServiceUnitPrice(0L);
            payTransBatchManager.updateByPrimaryKeyWithVersion(payTransBatch);
        }

        Long dayLimit = commonSysConfigHelper.getLong(CommonSysConfigKey.OPEN_ALIPAY_ACCOUNT_DAY_LIMIT);
        if (dayLimit == null || dayLimit == 0L) {
            return;
        }
        BigDecimal dayAmountLimit = new BigDecimal(100000L);
        Long defaultAmountLimit = commonSysConfigHelper.getLong(CommonSysConfigKey.ALIPAY_ACCOUNT_DAY_LIMIT_AMOUNT);
        if (defaultAmountLimit != null) {
            dayAmountLimit = new BigDecimal(defaultAmountLimit);
        }

        UserProfile userProfile = userProfileManager.getById(payTransBatch.getUserId());
        if (userProfile.getTransAmountDayLimit() != null && dayAmountLimit.compareTo(userProfile.getTransAmountDayLimit()) < 0) {
            dayAmountLimit = userProfile.getTransAmountDayLimit();
        }

        //有无超过日限制10万
        LocalDateTime day = LocalDateTime.now();
        LocalDateTime currentDayStartTime = LocalDateUtil.getDayStart(day);
        LocalDateTime currentDayEndTime = LocalDateUtil.getDayEnd(day);
        // 进行查询
        BigDecimal currentDayLimit = payTransBatchManager.getTransferLimit(currentDayStartTime, currentDayEndTime, alipayUser.getUserId(), alipayUser.getId());
        BigDecimal leftLimit = dayAmountLimit.subtract(currentDayLimit);
        if (leftLimit.compareTo(new BigDecimal(payTransBatch.getTotalTransAmount())) < 0) {
            throw new BusinessException(PoseidonErrorCode.ALIPAY_DAY_LIMIT, "支付宝账号（" + alipayUser.getAlipayNickName() + "）日限额10万，当日剩余额度" + leftLimit + "元，当前批次转账金额为" + payTransBatch.getTotalTransAmount() + "元，超过日限无法支付！");
        }
    }

    @Override
    public PayTransBatch closePayTransBatch(User user, Long id) {
        Preconditions.checkArgument(id != null);
        UserAccount userAccount = userAccountManager.getByIdWithLock(user.getId());

        PayTransBatch payTransBatch = payTransBatchManager.findById(user.getId(), id);
        if (payTransBatch == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "打款批次不存在");
        }
        //还未发起过转账
        if (payTransBatch.getStatus() == PayTransBatchStatus.IMPORTED) {
            payTransBatch.setStatus(PayTransBatchStatus.DISUSE);
            payTransBatch.setEndTime(LocalDateTime.now());
            payTransBatchManager.updateByPrimaryKeyWithVersion(payTransBatch);
            payTransManager.updateStatusByPayTransBatchId(user.getId(), payTransBatch.getId(), PayTransStatus.DISUSE, payTransBatch.getFree(), LocalDateTime.now());
            return payTransBatch;
        }
        if (payTransBatch.getStatus() == PayTransBatchStatus.DISUSE || payTransBatch.getStatus() == PayTransBatchStatus.INVALID) {
            return payTransBatch;
        }
        if (payTransBatch.getStatus() == PayTransBatchStatus.SUCCESS || payTransBatch.getStatus() == PayTransBatchStatus.PART_SUCCESS) {
            throw new BusinessException(PoseidonErrorCode.INVALID_CLOSE_STATUS, "当前批次已完成支付");
        }
        if ((payTransBatch.getStatus() != PayTransBatchStatus.WAIT_PAY && payTransBatch.getStatus() != PayTransBatchStatus.INIT) || payTransBatch.getLastSummaryId() == null) {
            throw new BusinessException(PoseidonErrorCode.INVALID_CLOSE_STATUS, "当前批次状态不支持关闭操作");
        }

        PayTransSummary payTransSummary = payTransSummaryManager.findById(user.getId(), payTransBatch.getLastSummaryId());
        if ((payTransSummary.getStatus() != PayTransBatchStatus.WAIT_PAY && payTransSummary.getStatus() != PayTransBatchStatus.INIT) || Strings.isNullOrEmpty(payTransSummary.getBatchTransId())) {
            throw new BusinessException(PoseidonErrorCode.INVALID_CLOSE_STATUS, "当前批次无法关闭 请联系客服");
        }

        AlipayUser alipayUser = alipayUserManager.getById(payTransSummary.getAlipayUserId());
        if (alipayUser == null || alipayUser.getIsDeleted() == 1) {
            //号被删掉了 直接允许删除
            return onAlipayUserNotExist(payTransBatch, payTransSummary, user, userAccount);
        }
        if (Strings.isNullOrEmpty(alipayUser.getAuthToken())) {
            throw new BusinessException(PoseidonErrorCode.INVALID_APP_AUTH_TOKEN, "你的支付宝账号尚未签约，请先签约");
        }

//        if (alipayUser.getExpiresIn().isBefore(LocalDateTime.now())) {
//            throw new BusinessException(PoseidonErrorCode.INVALID_APP_AUTH_TOKEN, "支付宝账号签约已过期，请重新签约");
//        }

        try {
            AlipayFundBatchCloseResponse resp = xpayAlipayClient.alipayFundBatchClose(alipayUser.getAuthToken(), payTransSummary.getBatchTransId());
            if (!resp.isSuccess()) {
                processAlipayFundBatchCloseError(resp, payTransSummary, payTransBatch);
            }

            //退还手续费
            long refund = refundServiceMoney(user, userAccount, payTransBatch);

            payTransBatch.setStatus(PayTransBatchStatus.DISUSE);
            payTransBatch.setEndTime(LocalDateTime.now());
            payTransBatch.setRefund(refund);
            payTransBatchManager.updateByPrimaryKeyWithVersion(payTransBatch);
            payTransManager.updateStatusByPayTransBatchId(user.getId(), payTransBatch.getId(), PayTransStatus.DISUSE, payTransBatch.getFree(), LocalDateTime.now());
            payTransSummary.setStatus(payTransBatch.getStatus());
            payTransSummary.setEndTime(payTransBatch.getEndTime());
            payTransSummaryManager.updateByPrimaryKeyWithVersion(payTransSummary);

            processCloseRelatedBusiness(user, payTransBatch);
        } catch (AlipayApiException e) {
            log.warn("closePayTransBatch error|userId={}|id={}|batchTransId={}", user.getId(), id, payTransSummary.getBatchTransId(), e);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, e.getErrMsg());
        }

        return payTransBatch;
    }

    /**
     * 处理关闭相关业务
     */
    private void processCloseRelatedBusiness(User user, PayTransBatch payTransBatch) {
        if (payTransBatch.getImportBatchNo().startsWith(TransBizTypeConstant.YT_AT)) {
            autoPayService.closeAutoPayTransBatchCallback(user, payTransBatch);
        }
    }

    private void processAlipayFundBatchCloseError(AlipayFundBatchCloseResponse resp, PayTransSummary payTransSummary, PayTransBatch payTransBatch) throws AlipayApiException {
        log.info("close batch failed|resp={}", resp.getSubCode() + "|" + resp.getSubMsg());
        if ("BATCH_ORDER_STATUS_INVALID".equals(resp.getSubCode())) {
            AlipayFundBatchDetailQueryResponse ret = alipayFundBatchService.allDetailQuery(payTransSummary.getAlipayUserId(), payTransSummary.getOutBatchNo());
            String batchStatus = ret.getBatchStatus();
            log.info("close batch failed then query batch status ={}|isSuccess={}|resp= {}", batchStatus, ret.isSuccess(), ret.getSubCode() + "|" + ret.getSubMsg());

            // INIT 接受 | WAIT_PAY 等待付款 不处理
            if (PayTransBatchStatus.SUCCESS.getValue().equals(batchStatus) || PayTransBatchStatus.PART_SUCCESS.getValue().equals(batchStatus)) {
                throw new BusinessException(PoseidonErrorCode.INVALID_CLOSE_STATUS, "当前批次已完成支付");
            }
            if (PayTransBatchStatus.DEALING.getValue().equals(batchStatus)) {
                throw new BusinessException(PoseidonErrorCode.BATCH_DEALING, "当前批次正在转账处理中");
            }
            if (PayTransBatchStatus.DISUSE.getValue().equals(batchStatus) || PayTransBatchStatus.INVALID.getValue().equals(batchStatus)) {
                return;
            }
            if ("BATCH_NOT_EXIST".equals(ret.getSubCode())) {
                //批次不存在 允许关闭
                return;
            }
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "批次当前无法关闭");
        } else if ("aop.invalid-app-auth-token".equals(resp.getSubCode()) || "isv.insufficient-user-permissions".equals(resp.getSubCode())) {
            //2天后可以关闭掉
            if (payTransBatch.getCreateTime().isBefore(LocalDateTime.now().minusDays(2L))) {
                return;
            }
            throw new BusinessException(PoseidonErrorCode.INVALID_APP_AUTH_TOKEN, resp.getMsg() + "|" + resp.getSubMsg());
        } else if (resp.getSubMsg() != null && resp.getSubMsg().contains("NO_ORDER_PERMISSION")) {
            //少数情况 支付宝账号做了什么更改导致无法关闭
            log.warn("processAlipayFundBatchCloseError NO_ORDER_PERMISSION|id={}", payTransBatch.getId());
            //2天后可以关闭掉
            if (payTransBatch.getCreateTime().isBefore(LocalDateTime.now().minusDays(2L))) {
                return;
            }
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "关闭失败：" + resp.getSubMsg() + "|" + resp.getSubCode());
        } else {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "关闭失败：" + resp.getSubMsg() + "|" + resp.getSubCode());
        }
    }

    private PayTransBatch onAlipayUserNotExist(PayTransBatch payTransBatch, PayTransSummary payTransSummary, User user, UserAccount userAccount) {
        //退还手续费
        long refund = refundServiceMoney(user, userAccount, payTransBatch);

        payTransBatch.setStatus(PayTransBatchStatus.DISUSE);
        payTransBatch.setEndTime(LocalDateTime.now());
        payTransBatch.setRefund(refund);
        payTransBatchManager.updateByPrimaryKeyWithVersion(payTransBatch);
        payTransManager.updateStatusByPayTransBatchId(user.getId(), payTransBatch.getId(), PayTransStatus.DISUSE, payTransBatch.getFree(), LocalDateTime.now());
        payTransSummary.setStatus(payTransBatch.getStatus());
        payTransSummary.setEndTime(payTransBatch.getEndTime());
        payTransSummaryManager.updateByPrimaryKeyWithVersion(payTransSummary);



        return payTransBatch;
    }

    private Long refundServiceMoney(User user, UserAccount userAccount, PayTransBatch payTransBatch) {
        //免费单不用退款
        if (payTransBatch.getFree()) {
            log.info("refundServiceMoney but batch is free|batchId={}", payTransBatch.getId());
            return 0L;
        }
        //查询历史有没有退过
        AccountDetail selected = accountDetailManager.findByRelatedId(user.getId(), payTransBatch.getLastSummaryId(), AccountBillType.PAY_TRANS_SERVICE_PRICE_REFUND);
        if (selected != null) {
            log.warn("refundServiceMoney account detail exist batch={}", SerializationUtil.obj2String(payTransBatch));
            return selected.getChange();
        }

        AccountDetail accountDetail = AccountDetail.getInstance(user.getId(), payTransBatch.getLastSummaryId());
        accountDetailHelper.initCommonAccountDetail(accountDetail, AccountBillType.PAY_TRANS_SERVICE_PRICE_REFUND, payTransBatch.getServicePrice(), "");

        accountService.onPay(user, userAccount, accountDetail);

        return payTransBatch.getServicePrice();
    }

    private void payServiceMoney(User user, UserAccount userAccount, PayTransBatch payTransBatch) {
        if (payTransBatch.getFree()) {
            log.info("payServiceMoney but batch is free|batchId={}", payTransBatch.getId());
            //扣除免费次数
            AccountDetail accountDetail = AccountDetail.getInstance(user.getId(), payTransBatch.getLastSummaryId());
            accountDetailHelper.initTransBatchAccountDetail(accountDetail, AccountBillType.PAY_TRANS_SERVICE_PRICE, -1L, "批量转账扣除批次次数");
            accountService.onPay(user, userAccount, accountDetail);
            return;
        }
        AccountDetail accountDetail = AccountDetail.getInstance(user.getId(), payTransBatch.getLastSummaryId());
        accountDetailHelper.initCommonAccountDetail(accountDetail, AccountBillType.PAY_TRANS_SERVICE_PRICE, -payTransBatch.getServicePrice(), "批量转账扣除余额");

        accountService.onPay(user, userAccount, accountDetail);

        payTransBatch.setHasPayService(true);
        payTransBatchManager.updateByPrimaryKeyWithVersion(payTransBatch);
    }

    @Override
    public void updatePayTransBatch(Long userId, Long summaryId) {
        User user = userManager.getById(userId);
        PayTransSummary summary = payTransSummaryManager.findById(user.getId(), summaryId);
        if (summary == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "批次不存在");
        }
        if (PayTransBatchStatus.isFinalStatus(summary.getStatus())) {
            log.warn("processPayTransBatch status error|status={}|userId={}|summaryId={}", summary.getStatus(), user.getId(), summaryId);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "批次状态已完成");
        }
        if (summary.getBatchTransId() == null) {
            log.warn("processPayTransBatch batchTransId null|userId={}|summaryId={}", user.getId(), summaryId);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "批次尚未发起支付");
        }

        try {
            AlipayFundBatchDetailQueryResponse resp = alipayFundBatchService.allDetailQuery(summary.getAlipayUserId(), summary.getOutBatchNo());
            String batchStatus = resp.getBatchStatus();
            if (batchStatus == null || !resp.isSuccess()) {
                log.warn("processPayTransBatch resp batch status null|userId={}|summaryId={}|resp={}", user.getId(), summaryId, resp.getErrorCode() + "|" + resp.getMsg() + "|" + resp.getSubCode() + "|" + resp.getSubMsg());
                throw new RuntimeException("processPayTransBatch resp batch status null|userId=" + userId + "|summaryId=" + summaryId);
            }
            // INIT 接受 | WAIT_PAY 等待付款 不处理
            if (PayTransBatchStatus.INIT.getValue().equals(batchStatus) || PayTransBatchStatus.WAIT_PAY.getValue().equals(batchStatus) || PayTransBatchStatus.DEALING.getValue().equals(batchStatus)) {
                log.info("processPayTransBatch resp batch status = {}|userId={}|summaryId={}", batchStatus, user.getId(), summaryId);
                return;
            }

            respProcess(user, summary, resp);
        } catch (Exception e) {
            log.error("processPayTransBatch error|userId={}|summaryId={}", user.getId(), summaryId, e);
            throw new RuntimeException("processPayTransBatch resp error");
        }
    }


    private void respProcess(User user, PayTransSummary summary, AlipayFundBatchDetailQueryResponse response) {
        List<AccDetailModel> accDetailList = response.getAccDetailList();
        List<String> outBizNos = StreamUtil.map(accDetailList, AccDetailModel::getOutBizNo);
        List<PayTrans> payTransList = outBizNos.size() == 0 ? Lists.newArrayList() : payTransManager.findByUserIdAndOutBizNoIn(summary.getUserId(), outBizNos);

        countAmountAndNum(summary, response.getAccDetailList());
        updatePayTrans(PayTransBatchStatus.of(response.getBatchStatus()), response.getAccDetailList(), payTransList);
        updateStatusRecordList(summary.getUserId(), summary.getId(), accDetailList);

        summary.setStatus(PayTransBatchStatus.of(response.getBatchStatus()));
        summary.setEndTime(LocalDateTime.now());
        payTransSummaryManager.updateByPrimaryKeyWithVersion(summary);

        //跟新批次
        PayTransBatch batch = payTransBatchManager.findById(summary.getUserId(), summary.getPayTransBatchId());
        batch.setStatus(summary.getStatus());
        batch.setEndTime(summary.getEndTime());
        batch.setSuccessCount(summary.getSuccessCount());
        batch.setFailCount(summary.getFailCount());
        batch.setSuccessAmount(summary.getSuccessAmount());
        batch.setFailedAmount(summary.getFailedAmount());

        //处理一下资金退款
        long refund = processRefund(user, batch);
        batch.setRefund(refund);

        //分佣收益计算
        calBenefit(batch, user, refund);

        payTransBatchManager.updateByPrimaryKeyWithVersion(batch);

        //回调通知
        processNotifyRecord(user, batch);

        //处理一些关联业务 比如收集收款
        processRelatedBusiness(user, batch, payTransList);
    }

    private void processRelatedBusiness(User user, PayTransBatch batch, List<PayTrans> payTransList) {
        if (Strings.isNullOrEmpty(batch.getImportBatchNo())) {
            return;
        }
        //收集收款
        processCollectionBatch(user, batch, payTransList);

        //自动付收款
        processAutoPayBatch(user, batch, payTransList);
    }

    private void processAutoPayBatch(User user, PayTransBatch batch, List<PayTrans> payTransList) {
        if (!batch.getImportBatchNo().startsWith(TransBizTypeConstant.YT_AT)) {
            return;
        }

        autoPayService.updatePayResult(user, batch, payTransList);
    }

    private void processCollectionBatch(User user, PayTransBatch batch, List<PayTrans> payTransList) {
        if (!batch.getImportBatchNo().startsWith(TransBizTypeConstant.CB)) {
            return;
        }
        collectionOrderService.updateCollectionBatch(user, batch, payTransList);
    }

    private void processNotifyRecord(User user, PayTransBatch batch) {
        UserProfile userProfile = userProfileManager.getById(user.getId());
        if (Strings.isNullOrEmpty(userProfile.getChargeNotifyUrl())) {
            return;
        }

        ChargeNotifyRecord record = chargeNotifyRecordManager.findByBatchId(batch.getId());
        if (record == null) {
            return;
        }
        record.setNextNotifyTime(LocalDateTime.now());
        record.setStatus(NotifyStatus.WAIT);

        if (userProfile.getApiVersion() != null && userProfile.getApiVersion() == OpenApiVersion.V2) {
            PayTransBatchV2Dto dto = new PayTransBatchV2Dto();
            BeanCopierUtil.copy(batch, dto);
            List<PayTrans> payTransList = payTransManager.listByPayTransBatchId(user.getId(), batch.getId());
            List<PayTransDto> payTransDtos = BeanCopierUtil.batchCopy(PayTrans.class, PayTransDto.class, payTransList);
            dto.setPayTransList(payTransDtos);
            record.setNotifyContent(SerializationUtil.obj2String(dto));
        } else {
            PayTransBatchDto dto = new PayTransBatchDto();
            BeanCopierUtil.copy(batch, dto);
            List<PayTrans> payTransList = payTransManager.listByPayTransBatchId(user.getId(), batch.getId());
            List<PayTransDto> payTransDtos = BeanCopierUtil.batchCopy(PayTrans.class, PayTransDto.class, payTransList);
            dto.setPayTransList(payTransDtos);
            record.setNotifyContent(SerializationUtil.obj2String(dto));
        }
        chargeNotifyRecordManager.update(record);
    }

    public void calBenefit(PayTransBatch batch, User user, long refund) {
        if (batch.getFree()) {
            return;
        }
        long benefit = batch.getServicePrice() - refund;
        if (benefit <= 0L) {
            return;
        }
        //非合伙人用户
        if (batch.getPartnerId() == null) {
            batch.setBenefitRatio(new BigDecimal(0));
            batch.setFatherBenefitRatio(new BigDecimal(0));
            batch.setUnitPartnerBenefit(0L);
            batch.setUnitFatherPartnerBenefit(0L);
            batch.setTotalPartnerBenefit(0L);
            batch.setTotalFatherPartnerBenefit(0L);
            batch.setTotalPlatformBenefit(batch.getServicePrice() - refund);
            return;
        }
        //结算合伙人和平台收益
        doCalPartnerBenefit(batch, user, refund);
    }

    private void doCalPartnerBenefit(PayTransBatch batch, User user, long refund) {
        if (batch.getFatherPartnerId() == null) {
            //一级合伙人商户走原来逻辑不改动
            doCalLevel1PartnerBenefit(batch, user, refund);
        } else {
            //二级合伙人商户
            doCalLevel2PartnerBenefit(batch, user, refund);
        }
    }

    private void doCalLevel2PartnerBenefit(PayTransBatch batch, User user, long refund) {
        batch.setBenefitRatio(batch.getBenefitRatio() != null ? batch.getBenefitRatio() : user.getBenefitRatio());
        batch.setFatherBenefitRatio(batch.getFatherBenefitRatio() != null ? batch.getFatherBenefitRatio() : user.getFatherBenefitRatio());
        batch.setUnitPartnerBenefit(batch.getUnitPartnerBenefit() != null ? batch.getUnitPartnerBenefit() : user.getPartnerBenefit());
        batch.setUnitFatherPartnerBenefit(batch.getUnitFatherPartnerBenefit() != null ? batch.getUnitFatherPartnerBenefit() : user.getFatherPartnerBenefit());

        if (batch.getMode() == null || batch.getMode() == ServicePayMode.FIXED_AMOUNT) {
            batch.setTotalPartnerBenefit(user.getPartnerBenefit() * batch.getSuccessCount());
            batch.setTotalFatherPartnerBenefit(user.getFatherPartnerBenefit() * batch.getSuccessCount());
            batch.setTotalPlatformBenefit(batch.getSuccessCount() * batch.getServiceRealPrice() - batch.getTotalPartnerBenefit() - batch.getTotalFatherPartnerBenefit());
        } else {
            long benefit = batch.getServicePrice() - refund;
            if (CommissionMode.COST_MODE.equals(batch.getCommissionMode())) {
                //先分二级合伙人
                BigDecimal partnerServiceRatio = batch.getServiceRatio().subtract(batch.getCostServiceRatio());
                batch.setTotalPartnerBenefit(new BigDecimal(batch.getSuccessAmount()).multiply(partnerServiceRatio).multiply(new BigDecimal(100)).setScale(0, RoundingMode.DOWN).longValue());

                //再分上级合伙人
                long leftBenefit = benefit - batch.getTotalPartnerBenefit();
                if (user.getFatherCommissionMode() == CommissionMode.FIXED_MODE) {
                    //固定比例
                    long chargeCost = new BigDecimal(leftBenefit).multiply(new BigDecimal("0.006")).multiply(user.getFatherBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                    if (chargeCost == 0L) {
                        chargeCost = 1L;//最少一分钱
                    }
                    log.info("doCalLevel2PartnerBenefit chargeCost={}|batchNo={}", chargeCost, batch.getImportBatchNo());
                    batch.setTotalFatherPartnerBenefit(new BigDecimal(leftBenefit).multiply(batch.getFatherBenefitRatio()).setScale(0, RoundingMode.DOWN).longValue() - chargeCost);

                    if (batch.getTotalFatherPartnerBenefit() < 0L) {
                        log.warn("doCalLevel2PartnerBenefit father partner benefit < 0|importBatchNo={}|benefit={}", batch.getImportBatchNo(), batch.getTotalFatherPartnerBenefit());
                        batch.setTotalFatherPartnerBenefit(0L);
                    }
                } else if (user.getFatherCommissionMode() == CommissionMode.COST_MODE) {
                    BigDecimal fatherServiceRatio = user.getFatherServiceRatio() ;
                    batch.setTotalFatherPartnerBenefit(new BigDecimal(batch.getSuccessAmount()).multiply(fatherServiceRatio).multiply(new BigDecimal(100)).setScale(0, RoundingMode.DOWN).longValue());
                }

                batch.setTotalPlatformBenefit(benefit - batch.getTotalPartnerBenefit() - batch.getTotalFatherPartnerBenefit());
            } else {
                //百分比模式
                //先分二级合伙人
                long chargeCost = new BigDecimal(benefit).multiply(new BigDecimal("0.006")).multiply(batch.getBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                if (chargeCost == 0L) {
                    chargeCost = 1L;//最少一分钱
                }
                log.info("doCalLevel2PartnerBenefit 1 chargeCost={}|batchNo={}", chargeCost, batch.getImportBatchNo());
                batch.setTotalPartnerBenefit(new BigDecimal(benefit).multiply(batch.getBenefitRatio()).setScale(0, RoundingMode.DOWN).longValue() - chargeCost);
                if (batch.getTotalPartnerBenefit() < 0L) {
                    log.warn("doCalLevel2PartnerBenefit 1  partner benefit < 0|importBatchNo={}|benefit={}", batch.getImportBatchNo(), batch.getTotalPartnerBenefit());
                    batch.setTotalPartnerBenefit(0L);
                }

                //再分上级合伙人
                long leftBenefit = benefit - batch.getTotalPartnerBenefit();

                //固定比例
                chargeCost = new BigDecimal(leftBenefit).multiply(new BigDecimal("0.006")).multiply(user.getFatherBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                if (chargeCost == 0L) {
                    chargeCost = 1L;//最少一分钱
                }
                log.info("doCalLevel2PartnerBenefit 1 chargeCost={}|batchNo={}", chargeCost, batch.getImportBatchNo());
                batch.setTotalFatherPartnerBenefit(new BigDecimal(leftBenefit).multiply(batch.getFatherBenefitRatio()).setScale(0, RoundingMode.DOWN).longValue() - chargeCost);

                if (batch.getTotalFatherPartnerBenefit() < 0L) {
                    log.warn("doCalLevel2PartnerBenefit 1 father partner benefit < 0|importBatchNo={}|benefit={}", batch.getImportBatchNo(), batch.getTotalFatherPartnerBenefit());
                    batch.setTotalFatherPartnerBenefit(0L);
                }

                batch.setTotalPlatformBenefit(benefit - batch.getTotalPartnerBenefit() - batch.getTotalFatherPartnerBenefit());
            }
        }

        if (batch.getTotalPlatformBenefit() < 0L) {
            log.error("calBenefit totalPlatformBenefit <= 0|batch={}", SerializationUtil.obj2String(batch.getTotalPlatformBenefit()));
            noticeHelper.sendSystemMonitorNotice("calBenefit 严重错误 平台收益小于0 请赶快处理！|batchId=" + batch.getId(), "text");
        }
    }

    private void doCalLevel1PartnerBenefit(PayTransBatch batch, User user, long refund) {
        batch.setBenefitRatio(batch.getBenefitRatio() != null ? batch.getBenefitRatio() : user.getBenefitRatio());
        batch.setFatherBenefitRatio(batch.getFatherBenefitRatio() != null ? batch.getFatherBenefitRatio() : user.getFatherBenefitRatio());
        batch.setUnitPartnerBenefit(batch.getUnitPartnerBenefit() != null ? batch.getUnitPartnerBenefit() : user.getPartnerBenefit());
        batch.setUnitFatherPartnerBenefit(batch.getUnitFatherPartnerBenefit() != null ? batch.getUnitFatherPartnerBenefit() : user.getFatherPartnerBenefit());

        if (batch.getMode() == null || batch.getMode() == ServicePayMode.FIXED_AMOUNT) {
            batch.setTotalPartnerBenefit(user.getPartnerBenefit() * batch.getSuccessCount());
            batch.setTotalFatherPartnerBenefit(user.getFatherPartnerBenefit() * batch.getSuccessCount());
            batch.setTotalPlatformBenefit(batch.getSuccessCount() * batch.getServiceRealPrice() - batch.getTotalPartnerBenefit() - batch.getTotalFatherPartnerBenefit());
        } else {
            long benefit = batch.getServicePrice() - refund;
            if (CommissionMode.COST_MODE.equals(batch.getCommissionMode())) {
                //先算合伙人收益 再算平台收益
                BigDecimal partnerServiceRatio = batch.getServiceRatio().subtract(batch.getCostServiceRatio());
                batch.setTotalPartnerBenefit(new BigDecimal(batch.getSuccessAmount()).multiply(partnerServiceRatio).multiply(new BigDecimal(100)).setScale(0, RoundingMode.DOWN).longValue());
                batch.setTotalFatherPartnerBenefit(0L);
                if (batch.getTotalPartnerBenefit() > benefit) {
                    noticeHelper.sendSystemMonitorNotice("safe pay calBenefit 平台收益计算可能存在问题 请观察改记录！|batchId=" + batch.getId(), "text");
                    batch.setTotalPartnerBenefit(benefit);
                }
                batch.setTotalPlatformBenefit(benefit - batch.getTotalPartnerBenefit());
            } else if (CommissionMode.STAT_MODE.equals(batch.getCommissionMode())) {
                batch.setTotalPlatformBenefit(benefit);
                batch.setTotalPartnerBenefit(0L);
                batch.setTotalFatherPartnerBenefit(0L);
            } else {
                //百分比模式
                long chargeCost = new BigDecimal(benefit).multiply(new BigDecimal("0.006")).multiply(batch.getBenefitRatio()).setScale(0, RoundingMode.HALF_UP).longValue();
                if (chargeCost == 0L) {
                    chargeCost = 1L;//最少一分钱
                }
                log.info("doCalPartnerBenefit chargeCost={}|batchNo={}", chargeCost, batch.getImportBatchNo());
                batch.setTotalPartnerBenefit(new BigDecimal(benefit).multiply(batch.getBenefitRatio()).setScale(0, RoundingMode.DOWN).longValue() - chargeCost);
                if (batch.getTotalPartnerBenefit() < 0L) {
                    log.warn("doCalPartnerBenefit partner benefit < 0|importBatchNo={}|benefit={}", batch.getImportBatchNo(), batch.getTotalPartnerBenefit());
                    batch.setTotalPartnerBenefit(0L);
                }
                batch.setTotalFatherPartnerBenefit(new BigDecimal(benefit).multiply(batch.getFatherBenefitRatio()).setScale(0, RoundingMode.DOWN).longValue());
                batch.setTotalPlatformBenefit(benefit - batch.getTotalPartnerBenefit() - batch.getTotalFatherPartnerBenefit());
            }
        }

        if (batch.getTotalPlatformBenefit() < 0L && batch.getServiceUnitPrice() != 0L && batch.getSuccessCount() != 0L) {
            log.error("calBenefit totalPlatformBenefit <= 0|batch={}", SerializationUtil.obj2String(batch.getTotalPlatformBenefit()));
            noticeHelper.sendSystemMonitorNotice("calBenefit 严重错误 平台收益小于0 请赶快处理！|batchId=" + batch.getId(), "text");
        }
    }

    private long processRefund(User user, PayTransBatch batch) {
        log.info("respProcess batch={}", SerializationUtil.obj2String(batch));
        //免费批次不退款
        if (batch.getFree()) {
            log.info("processRefund but batch is free|batchId={}", batch.getId());
            return 0L;
        }
        if (batch.getFailCount() == null || batch.getFailCount() == 0L) {
            return 0L;
        }
        //查询历史有没有退过
        AccountDetail selected = accountDetailManager.findByRelatedId(user.getId(), batch.getLastSummaryId(), AccountBillType.PAY_TRANS_SERVICE_PRICE_REFUND);
        if (selected != null) {
            log.warn("account detail exist batch={}", SerializationUtil.obj2String(batch));
            return selected.getChange();
        }

        long refund;
        if (batch.getMode() == null || batch.getMode() == ServicePayMode.FIXED_AMOUNT) {
            refund = batch.getFailCount() * batch.getServiceUnitPrice();
        } else {
            refund = new BigDecimal(batch.getFailedAmount()).multiply(batch.getServiceRatio()).multiply(new BigDecimal(100)).setScale(0, RoundingMode.UP).longValue();
        }

        AccountDetail accountDetail = AccountDetail.getInstance(user.getId(), batch.getLastSummaryId());
        accountDetailHelper.initCommonAccountDetail(accountDetail, AccountBillType.PAY_TRANS_SERVICE_PRICE_REFUND, refund, "");
        UserAccount userAccount = userAccountManager.getByIdWithLock(user.getId());
        accountService.onPay(user, userAccount, accountDetail);

        return refund;
    }

    private void updateStatusRecordList(Long userId, Long summaryId, List<AccDetailModel> accDetailList) {
        List<PayTransRecord> records = payTransRecordManager.listByUserIdAndSummaryId(userId, summaryId);
        Map<String, PayTransRecord> recordMap = StreamUtil.toMap(records, PayTransRecord::getOutBizNo);

        List<PayTransRecord> list = Lists.newArrayList();
        for (AccDetailModel accDetail : accDetailList) {
            PayTransRecord record = recordMap.get(accDetail.getOutBizNo());
            record.setStatus(PayTransStatus.of(accDetail.getStatus()));
            record.setEndTime(LocalDateTime.now());
            record.setDetailId(accDetail.getDetailId());
            record.setErrorCode(accDetail.getErrorCode());
            record.setErrorMsg(accDetail.getErrorMsg());
            list.add(record);
        }

        payTransRecordManager.batchUpdate(list);
    }

    private void updatePayTrans(PayTransBatchStatus batchStatus, List<AccDetailModel> accDetailList, List<PayTrans> payTransList) {
        Map<String/*outBizNo*/, PayTrans> payTransMap = StreamUtil.toMap(payTransList, PayTrans::getOutBizNo);
        List<PayTrans> list = Lists.newArrayList();
        for (AccDetailModel accDetail : accDetailList) {
            PayTrans payTrans = payTransMap.get(accDetail.getOutBizNo());
            PayTransStatus status = PayTransStatus.of(accDetail.getStatus());
            if (PayTransBatchStatus.DISUSE.equals(batchStatus)) {
                status = PayTransStatus.DISUSE;
            }
            payTrans.setDetailId(accDetail.getDetailId());
            payTrans.setErrorCode(accDetail.getErrorCode());
            payTrans.setErrorMsg(payTransErrorMsgHelper.getErrorMsg(payTrans.getErrorCode(), accDetail.getErrorMsg()));
            payTrans.setStatus(status);
            payTrans.setEndTime(LocalDateTime.now());
            list.add(payTrans);
        }
        payTransManager.batchUpdate(list);
    }

    private void countAmountAndNum(PayTransSummary summary, List<AccDetailModel> accDetailList) {
        Long successCount = 0L;
        BigDecimal successAmount = new BigDecimal(0);
        Long failCount = 0L;
        BigDecimal failAmount = new BigDecimal(0);

        for (AccDetailModel accDetail : accDetailList) {
            if (PayTransStatus.DEALING.getValue().equals(accDetail.getStatus())) { //处理中，跳过。
                return;
            }
            if (PayTransStatus.SUCCESS.getValue().equals(accDetail.getStatus())) {
                successCount++;
                successAmount = successAmount.add(new BigDecimal(accDetail.getTransAmount()));
            } else {
                failCount++;
                failAmount = failAmount.add(new BigDecimal(accDetail.getTransAmount()));
            }
        }
        summary.setSuccessCount(successCount);
        summary.setFailCount(failCount);
        summary.setSuccessAmount(successAmount.toString());
        summary.setFailedAmount(failAmount.toString());
    }

    private void alipayFundBatchCreate(PayTransSummary payTransSummary, List<PayTransRecord> payTransRecords, AlipayUser alipayUser) {
        TransOrderModel transOrderModel = buildTransOrderModel(payTransSummary, payTransRecords);
        log.info("alipayFundBatchCreate params id={}|transOrderModel={}", payTransSummary.getPayTransBatchId(), GsonUtil.getGson().toJson(transOrderModel));
        AlipayFundBatchCreateResponse response;
        try {
            response = xpayAlipayClient.alipayFundBatchCreate(alipayUser.getAuthToken(), transOrderModel);
        } catch (AlipayApiException e) {
            log.warn("alipayFundBatchCreate error|id={}", payTransSummary.getPayTransBatchId(), e);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "打款失败：" + e.getErrMsg());
        }
        log.info("alipayFundBatchCreate resp id={}|resp={}", payTransSummary.getPayTransBatchId(), SerializationUtil.obj2String(response));

        if (!response.isSuccess()) {
            log.warn("alipayFundBatchCreate failed userId={}|id={}|errorMsg={}", payTransSummary.getUserId(), payTransSummary.getPayTransBatchId(), response.getSubMsg() + "|" + response.getMsg());
            if ("aop.invalid-app-auth-token".equals(response.getSubCode())){
                throw new BusinessException(PoseidonErrorCode.INVALID_APP_AUTH_TOKEN,"支付宝账号签约已失效，请重新签约");
            }
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "打款失败：" + response.getSubMsg() + "|" + response.getMsg());
        }

        payTransSummary.setBatchTransId(response.getBatchTransId());
        payTransSummary.setStatus(PayTransBatchStatus.of(response.getStatus()));
        payTransSummaryManager.updateByPrimaryKeyWithVersion(payTransSummary);

        for (PayTransRecord payTransRecord : payTransRecords) {
            payTransRecord.setBatchTransId(response.getBatchTransId());
        }

        payTransRecordManager.batchSave(payTransRecords);
    }

    private TransOrderModel buildTransOrderModel(PayTransSummary payTransSummary, List<PayTransRecord> payTransRecords) {
        TransOrderModel transOrderModel = TransOrderModel.getInstance();
        transOrderModel.setOutBatchNo(payTransSummary.getOutBatchNo());
        transOrderModel.setTotalTransAmount(payTransSummary.getTotalTransAmount());
        transOrderModel.setTotalCount(payTransSummary.getTotalCount().toString());
        transOrderModel.setProductCode(payTransSummary.getProductCode());
        transOrderModel.setBizScene(payTransSummary.getBizScene());
        transOrderModel.setOrderTitle(payTransSummary.getOrderTitle());
        //没有过期时间设置一个默认的过期时间48小时
        String defaultTimeExpire = LocalDateUtil.getDateTimeAsString(LocalDateTime.now().plusHours(48L), "yyyy-MM-dd HH:mm");
        transOrderModel.setTimeExpire(payTransSummary.getTimeExpire() != null ? payTransSummary.getTimeExpire() : defaultTimeExpire);
        transOrderModel.setRemark(payTransSummary.getRemark());
        List<TransOrderModel.TransOrderDetail> transOrderDetails = Lists.newArrayList();
        for (PayTransRecord record : payTransRecords) {
            TransOrderModel.TransOrderDetail detail = TransOrderModel.TransOrderDetail.getInstance();
            detail.setOutBizNo(record.getOutBizNo());
            detail.setTransAmount(record.getTransAmount());
            detail.setRemark(record.getRemark());

            TransOrderModel.PayeeInfo payeeInfo = TransOrderModel.PayeeInfo.getInstance();
            payeeInfo.setIdentity(record.getIdentity());
            payeeInfo.setIdentityType(record.getIdentityType());
            payeeInfo.setName(record.getName());

            detail.setPayeeInfo(payeeInfo);

            transOrderDetails.add(detail);
        }
        transOrderModel.setTransOrderList(transOrderDetails);
        return transOrderModel;
    }

    private List<PayTransRecord> createPayTransRecords(PayTransSummary payTransSummary) {
        List<PayTrans> payTrans = payTransManager.listByPayTransBatchId(payTransSummary.getUserId(), payTransSummary.getPayTransBatchId());
        List<PayTransRecord> payTransRecords = Lists.newArrayList();
        for (PayTrans trans : payTrans) {
            trans.setAlipayUserId(payTransSummary.getAlipayUserId());
            trans.setAlipayNickName(payTransSummary.getAlipayNickName());

            PayTransRecord payTransRecord = PayTransRecord.getInstance();
            payTransRecord.setUserId(trans.getUserId());
            payTransRecord.setPartnerId(trans.getPartnerId());
            payTransRecord.setMobile(trans.getMobile());
            payTransRecord.setAlipayUserId(payTransSummary.getAlipayUserId());
            payTransRecord.setAlipayNickName(payTransSummary.getAlipayNickName());
            payTransRecord.setPayTransId(trans.getId());
            payTransRecord.setBatchTransId(null);
            payTransRecord.setSummaryId(payTransSummary.getId());
            payTransRecord.setPayTransBatchId(trans.getPayTransBatchId());
            payTransRecord.setOutBatchNo(payTransSummary.getOutBatchNo());
            payTransRecord.setImportBatchNo(payTransSummary.getImportBatchNo());
            payTransRecord.setOutBizNo(trans.getOutBizNo());
            payTransRecord.setImportBizNo(trans.getImportBizNo());
            payTransRecord.setTransAmount(trans.getTransAmount());
            payTransRecord.setRemark(trans.getRemark());
            payTransRecord.setIdentity(trans.getIdentity());
            payTransRecord.setIdentityType(trans.getIdentityType());
            payTransRecord.setName(trans.getName());
            payTransRecord.setStatus(PayTransStatus.WAIT_PAY);
            payTransRecord.setVersion(0L);

            payTransRecords.add(payTransRecord);
        }

        //支付宝信息跟新一下
        payTransManager.batchUpdate(payTrans);
        return payTransRecords;
    }

    private PayTransSummary createPayTransSummary(User user, AlipayUser alipayUser, PayTransBatch payTransBatch) {
        PayTransSummary payTransSummary = PayTransSummary.getInstance();
        payTransSummary.setUserId(user.getId());
        payTransSummary.setPartnerId(user.getPartnerId());
        payTransSummary.setOtherTrans(false);
        payTransSummary.setAlipayUserId(alipayUser.getId());
        payTransSummary.setAlipayNickName(alipayUser.getAlipayNickName());
        payTransSummary.setMobile(user.getMobile());
        payTransSummary.setOutBatchNo(null);
        payTransSummary.setBatchTransId(null);
        payTransSummary.setPayTransBatchId(payTransBatch.getId());
        payTransSummary.setImportBatchNo(payTransBatch.getImportBatchNo());
        payTransSummary.setServiceUnitPrice(payTransBatch.getServiceUnitPrice());
        payTransSummary.setServicePrice(payTransBatch.getServicePrice());
        payTransSummary.setTotalTransAmount(payTransBatch.getTotalTransAmount());
        payTransSummary.setTotalCount(payTransBatch.getTotalCount());
        payTransSummary.setSuccessAmount("0");
        payTransSummary.setSuccessCount(0L);
        payTransSummary.setFailedAmount("0");
        payTransSummary.setFailCount(0L);
        payTransSummary.setProductCode("BATCH_API_TO_ACC");
        payTransSummary.setBizScene("MESSAGE_BATCH_PAY");
        payTransSummary.setOrderTitle(payTransBatch.getOrderTitle());
        payTransSummary.setTimeExpire(payTransBatch.getTimeExpire());
        payTransSummary.setRemark(payTransBatch.getRemark());
        payTransSummary.setStatus(PayTransBatchStatus.IMPORTED);
        payTransSummary.setVersion(0L);

        payTransSummaryManager.save(payTransSummary);
        payTransBatch.setLastSummaryId(payTransSummary.getId());
        payTransBatch.setAlipayUserId(payTransSummary.getAlipayUserId());
        payTransBatch.setAlipayNickName(payTransSummary.getAlipayNickName());
        payTransBatchManager.updateByPrimaryKeyWithVersion(payTransBatch);
        return payTransSummary;
    }
}
